package com.lxj.realm;

import com.lxj.common.Constant;
import com.lxj.domain.ActiveUser;
import com.lxj.domain.SysPermission;
import com.lxj.domain.SysRole;
import com.lxj.domain.SysUser;
import com.lxj.service.PermissionService;
import com.lxj.service.RoleService;
import com.lxj.service.UserService;
import com.lxj.vo.TreeNode;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author lxj
 * @date 2021/6/16 14:21
 */
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    /**
     * 鉴权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        ActiveUser primaryPrincipal = (ActiveUser) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setStringPermissions(primaryPrincipal.getPerms());
        simpleAuthorizationInfo.setRoles(primaryPrincipal.getRoles());
        return simpleAuthorizationInfo;
    }

    /**
     * 登录
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 1 获取用户的名称
        String username = token.getPrincipal().toString();
        // 2 使用用户名查询用户
        SysUser user = userService.findUserByUsername(username);
        // 3 判断用户是否为null
        if(user == null){
            return null;
        }
        ActiveUser activeUser = new ActiveUser();
        activeUser.setUser(user);
        // 查询用户的所有角色的tag放在里面
        activeUser.setRoles(getUserRole(user.getId()));
        //查询用户的所有权限的type放在里面
        activeUser.setPerms(getUserPerms(user.getId()));
        // 查询用户的所有菜单
        activeUser.setMenus(getUserMenus(user.getId()));
        return new SimpleAuthenticationInfo(activeUser,user.getPassword(), ByteSource.Util.bytes(Constant.MD5_SALT),username);
    }

    /**
     * 通过用户的id 查询用户的菜单
     * 菜单： 目录 + 菜单数据
     *
     * @param id
     * @return
     */
    private List<TreeNode> getUserMenus(Integer id) {
        List<SysPermission> sysPermissions = permissionService.getPermsByUserIdAndType(id, Arrays.asList(0, 1));
        return permissionService.convertTreeNode(sysPermissions);
    }

    /**
     * 通过用户的id 查询用户的权限
     * @param id
     * @return
     */
    private Set<String> getUserPerms(Integer id) {
        List<SysPermission> sysPermissions = permissionService.getPermsByUserIdAndType(id, Arrays.asList(2));
        return sysPermissions.stream().map(SysPermission::getTag).collect(Collectors.toSet());
    }

    /**
     * 通过用户id 查询用户角色
     *
     * @param id
     * @return
     */
    private Set<String> getUserRole(Integer id) {
        List<SysRole> sysRoles = roleService.findByUserId(id);
        Set<String> tags = null;
        if (sysRoles != null && sysRoles.size() > 0) {
            tags = new HashSet<>();
            for (SysRole sysRole : sysRoles) {
                String tag = sysRole.getTag();
                tags.add(tag);
            }
            return tags;
        }
        return null;
    }

    public static void main(String[] args) {
        Md5Hash hash = new Md5Hash("123456", "lxj", 2);
        System.out.println(hash.toHex());
    }
}
